package com.easylinkin.linkappapi.lobar.util;

import com.google.common.base.Strings;

import java.util.stream.IntStream;

/**
 * 身份证号码验证
 * 1、号码的结构
 * 公民身份号码是特征组合码，由十七位数字本体码和一位校验码组成。从左至右依次为：六位数字地址码，
 * 八位数字出生日期码，三位数字顺序码和一位数字校验码。
 * 2、地址码(前六位数）
 * 表示编码对象常住户口所在县(市、旗、区)的行政区划代码，按GB/T2260的规定执行。
 * 3、出生日期码（第七位至十四位）
 * 表示编码对象出生的年、月、日，按GB/T7408的规定执行，年、月、日代码之间不用分隔符。
 * 4、顺序码（第十五位至十七位）
 * 表示在同一地址码所标识的区域范围内，对同年、同月、同日出生的人编定的顺序号，
 * 顺序码的奇数分配给男性，偶数分配给女性。
 * 5、校验码（第十八位数）
 * （1）十七位数字本体码加权求和公式 S = Sum(Ai Wi), i = 0, , 16 ，先对前17位数字的权求和 ;
 * Ai:表示第i位置上的身份证号码数字值; Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
 * （2）计算模 Y = mod(S, 11)
 * （3）通过模( 0 1 2 3 4 5 6 7 8 9 10)得到对应的校验码 Y:1 0 X 9 8 7 6 5 4 3 2
 */
public class IdentityUtils {

  // 身份证校验码
  private static final int[] COEFFICIENT_ARRAY = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

  // 身份证号的尾数规则
  private static final String[] IDENTITY_MANTISSA = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};

  private static final String IDENTITY_PATTERN = "^[0-9]{17}[0-9Xx]$";

  //身份证号脱敏
  public static String desensitizedIdNumber(String idNumber){
    if (!Strings.isNullOrEmpty(idNumber)) {
      if (idNumber.length() == 15){
        idNumber = idNumber.replaceAll("(\\w{6})\\w*(\\w{3})", "$1******$2");
      }
      if (idNumber.length() == 18){
        idNumber = idNumber.replaceAll("(\\w{6})\\w*(\\w{3})", "$1*********$2");
      }
    }
    return idNumber;
  }
  //身份证号校验
  public static boolean isLegalPattern(String identity) {
    if (identity == null) {
      return false;
    }

    if (identity.length() != 18) {
      return false;
    }

    if (!identity.matches(IDENTITY_PATTERN)) {
      return false;
    }
    // 将字符串对象中的字符转换为一个字符数组
    char[] chars = identity.toCharArray();
    long sum = IntStream.range(0, 17).map(index -> {
      char ch = chars[index];
      // 通俗理解：digit()是个边界值判断，不过边界返回字符数字本身数值，超过边界即返回 -1.
      int digit = Character.digit(ch, 10);
      int coefficient = COEFFICIENT_ARRAY[index];
      return digit * coefficient;
    }).summaryStatistics().getSum();

    // 计算出的尾数索引
    int mantissaIndex = (int) (sum % 11);
    String mantissa = IDENTITY_MANTISSA[mantissaIndex];

    String lastChar = identity.substring(17);
    if (lastChar.equalsIgnoreCase(mantissa)) {
      return true;
    } else {
      return false;
    }
  }
}
